/*	$Id: pforge.c 6 2008-07-29 02:30:10Z phrakt $	*/
/*
 * Copyright (c) 2003, 2005 Jean-Francois Brousseau <jfb@openbsd.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/types.h>

#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <sysexits.h>

#include "if.h"
#include "log.h"
#include "mib.h"
#include "pbuf.h"
#include "conf.h"
#include "dlink.h"
#include "proto.h"
#include "module.h"
#include "pforge.h"
#include "private.h"

#define PFORGE_STATE_NONE          0
#define PFORGE_STATE_INITIALIZED   1
#define PFORGE_STATE_SHUTDOWN      2

static int pforge_state = PFORGE_STATE_NONE;
static char *pforge_conf = PF_PATH_CONF;


/* log channel for the library */
pf_logchan_t pforge_chan;


const int pforge_version_major;
const int pforge_version_minor;


struct pf_mib_desc pf_version_mib[] = {
	{ "major",	PFMIB_TYPE_UINT,	NULL,	},
	{ "minor",	PFMIB_TYPE_UINT,	NULL,	},
	{ "release",	PFMIB_TYPE_UINT,	NULL,	},
};

struct pf_mib_desc pf_core_mibvars[] = {
	{ "version",	PFMIB_TYPE_BRANCH,	pf_version_mib,	},
	{ "segvprot",	PFMIB_TYPE_BOOL,	NULL,	},
	{ NULL,		0,			NULL,	},
};


/*
 * Top-level entries for the Packet Forge MIB.
 *
 */
struct pf_mib_desc pf_core_mib[] = {
	{ "core",	PFMIB_TYPE_BRANCH,	pf_core_mibvars,	},
	{ "modules",	PFMIB_TYPE_BRANCH,	NULL			},
	{ "net",	PFMIB_TYPE_BRANCH,	NULL			},
	{ NULL,		0,			NULL,			},
};





static int  pf_modtab_hdlr  (int, char **);
static int  pf_modpath_hdlr (int, char **);
static int  pf_loadmod_hdlr (int, char **);


/*
 * pf_init()
 *
 * Initialize the Packet Forge library.
 * Returns PF_OK on success, or PF_ERROR on error.
 */
int
pf_init(void)
{
	char *env;
	pfmib_oid_t oid;

	if (pforge_state == PFORGE_STATE_INITIALIZED)
		return (0);

	if ((pf_err_init() < 0) || (pf_ctx_init() < 0))
		return (PF_ERROR);

	if (pf_log_init() < 0)
		return (PF_ERROR);

	if ((pf_mib_init() < 0) ||
	    (pf_mib_loaddesc(PFMIB_OID_ROOT, pf_core_mib) < 0))
		return (PF_ERROR);

	if ((pf_rand_init() < 0) || (pf_netif_init() < 0) ||
	    (pf_dlink_init() < 0) || (pf_pbuf_init() < 0) ||
	    (pf_proto_init() < 0) || (pf_mod_init() < 0))
		return (PF_ERROR);

	/*
	 * Read our global configuration file.  The default path can be
	 * overrident with the environment variable specified by PF_ENV_CONF.
	 */
	if ((env = getenv(PF_ENV_CONF)) != NULL)
		pforge_conf = env;

	if (pf_readconf(pforge_conf) < 0)
		return (PF_ERROR);

	pforge_state = PFORGE_STATE_INITIALIZED;

	/* make sure cleanup gets called at end of program */
	(void)atexit(pf_cleanup);

	return (PF_OK);
}


/*
 * pf_cleanup()
 *
 */
void
pf_cleanup(void)
{
	if (pforge_state != PFORGE_STATE_INITIALIZED)
		return;

	pforge_state = PFORGE_STATE_SHUTDOWN;

	pf_mod_cleanup();
	pf_netif_cleanup();
	pf_pbuf_cleanup();
}


/*
 * pf_readconf()
 *
 * Read the Packet Forge configuration file <path>.
 * Returns 0 on success, -1 on failure.
 */
int
pf_readconf(const char *path)
{
	int ret;
	int flags = CONF_STRICT | CONF_VARSUBST | CONF_MULTILINE;
	CONF *cf;

	ret = 0;

	pf_log(pforge_chan, PFLOG_DEBUG, "reading configuration file %s", path);
	if ((cf = pf_conf_alloc(CONF_STYLE_STD, flags)) == NULL)
		return (-1);

	pf_log(pforge_chan, PFLOG_DEBUG, "setting up directives");
	if ((pf_conf_setdir(cf, "loadmod", pf_loadmod_hdlr) < 0) ||
	    (pf_conf_setdir(cf, "modpath", pf_modpath_hdlr) < 0) ||
	    (pf_conf_setdir(cf, "modtab", pf_modtab_hdlr) < 0))
		ret = -1;
	else if (pf_conf_parse(cf, path) < 0)
		ret = -1;

	pf_conf_free(cf);

	return (ret);
}

/*
 * pf_modtab_hdlr()
 */
static int
pf_modtab_hdlr(int argc, char **argv)
{
	if (argc < 3) {
		pf_log(pforge_chan, PFLOG_ERROR,
		    "not enough arguments to `%s' directive", argv[0]);
		return (-1);
	}


	return (0);
}

/*
 * pf_loadmod_hdlr()
 *
 * Handler for the `loadmod' configuration directive.
 */
static int
pf_loadmod_hdlr(int argc, char **argv)
{
	if (argc < 2) {
		pf_log(pforge_chan, PFLOG_ERROR, "not enough arguments to `%s' directive",
		    argv[0]);
		return (-1);
	}

	pf_mod_load(argv[1], 0);

	return (0);
}

/*
 * pf_modpath_hdlr()
 *
 * Handler for the `modpath' configuration directive, which specifies a
 * path to a directory to include in the standard module search paths.
 */
static int
pf_modpath_hdlr(int argc, char **argv)
{
	int ret;

	if (argc != 2) {
		pf_log(pforge_chan, PFLOG_ERROR,
		    "invalid argument count to `modpath' directive");
		ret = -1;
	} else if (pf_mod_addpath(argv[1]) < 0)
		ret = -1;
	else
		ret = 0;

	return (ret);


}
